#!/usr/bin/env perl

use strict;
use warnings;

package Nx::Build;

=head1 NAME

build.pl - build the uv project

=head1 SYNOPSIS

  ./build.pl [options]

Rebuild uv4 project.
 
=head1 OPTIONS

B<Global options:>

=over

=item --uv-path

uv4.exe file path

=item --project

project file name

=item --show-ui

show uv4 window

=back

=cut

use Carp         qw( confess             );
use English      qw( -no_match_vars      );
use Getopt::Long qw( GetOptionsFromArray );
use Pod::Usage   qw( pod2usage           );
use File::Spec   qw( rel2abs             );

my @merge_options = (
    ["--pcb=a1",  "--output=hex/f58x_picker.h03","--input=bootloader/tmp/a1/f58x_b1_a1.H03","--input=application/tmp/a1/release/f58x_picker_a1_release.H03"],
    ["--pcb=a1", "-d", "--output=hex/f58x_picker.h03","--input=bootloader/tmp/a1/f58x_b1_a1.H03","--input=application/tmp/a1/debug/f58x_picker_a1_debug.H03"],
);

sub new
{
    my ($class, @arguments) = @_;

    my $self = {};
    bless $self, $class;
    $self->parse_arguments(@arguments);

    return $self;
}

# Like `system', but possibly log the command, and die on non-zero exit code
sub exe
{
    my ($self, @cmd) = @_;

    if (!$self->{quiet}) {
        print "+ @cmd\n";
    }

    if (system(@cmd) != 0) {
        confess "@cmd exited with status $CHILD_ERROR";
    }

    return;
}

sub parse_arguments
{
    my ($self, @args) = @_;
    
    %{$self} = (%{$self},
        'log' => $ENV{TMP} . "/log.txt",
    );

    GetOptionsFromArray(\@args,
        'uv-path=s'         =>  \$self->{qw{ uv-path           }},
        'project'           =>  \$self->{qw{ project           }},
        'show-ui'           =>  \$self->{qw{ show-ui           }},
        'quiet'             =>  \$self->{qw{ quiet             }},

        'help|?'            =>  sub { pod2usage(1);               },
    ) || pod2usage(2);

    # UV4.exe
    if (!$self->{'uv-path'}) {
        my @uv_path = (
            "c:/Keil/UV4/uv4.exe",
            "c:/Keil_v4/UV4/uv4.exe",
            "c:/Keil_v5/UV4/uv4.exe",
            "c:/Keil4/UV4/uv4.exe"    
            );
            
        for (@uv_path) {
            if (-e) {
                $self->{'uv-path'} = $_;
                last;
            }
        }
    }
    
    die "uv4.exe not found.\n" if !defined($self->{'uv-path'});
    die "$self->{'uv-path'} does not exist.\n" if (!-e $self->{'uv-path'});
    
    #project
    if (!$self->{'project'}) {
        $self->{'project'} = glob "*.uvmpw";
    }
    
    die "project file not specified.\n" if (!defined($self->{'project'}));
    die "$self->{'project'} does not exist.\n" if (!-e $self->{'project'});

    return;
}

sub build
{
    my ($self) = @_;
    
    my @cmd = ($self->{'uv-path'}, '-r', $self->{'project'}, '-z', '-o', "$self->{'log'}");
    push @cmd, '-j0' if (!$self->{'show-ui'});
    $self->exe(@cmd);

    my @logs = ($self->{log});
    my $targets = 0;    
    my $errors = 0;
    my $warnings = 0;

    # 将编译结果输出到终端, 并计数编译错误和警告
    for (@logs){
        my $log = $_;
        open(my $in, "<", $_) or die "Can't open $_: $!\n";
        while(<$in>) {
            if (/(\d+)\s*Error\(s\),\s*(\d+)\s*Warning\(s\)\./) {
                $targets ++;
                $errors += $1;
                $warnings += $2;
            }
            print $_ if (!$self->{quiet});
        }
        close $in;
        unlink $log;
    }
    
    $self->{targets} = $targets;
    $self->{errors} = $errors;
    $self->{warnings} = $warnings;
    
    print "$targets Target(s) rebuild - $errors Error(s), $warnings Warning(s).\n";
}

sub merge
{
    my ($self) = @_;
        
    for(@merge_options) {
        $self->exe('perl', 'merge.pl', @{$_});
    }
}

sub run
{
    my ($self) = @_;
    
    $self->build;
    $self->merge;
}

#==============================================================================

Nx::Build->new(@ARGV)->run if (!caller);
1;
